package com.example.zhibo.common;

import java.io.BufferedReader;
import java.io.InputStreamReader;

import org.bytedeco.javacv.FrameGrabber;
import org.bytedeco.javacv.VideoInputFrameGrabber;
import ws.schild.jave.process.ProcessWrapper;
import ws.schild.jave.process.ffmpeg.DefaultFFMPEGLocator;

import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.Mixer;
import java.io.IOException;
import java.util.Date;
import java.util.List;


public class FfmpegUtil {
    private static ProcessWrapper ffmpeg; // 定义全局变量
//  rtmp://127.0.0.1:1935/live/
//String Webcam = "USB2.0 HD UVC WebCam";
//String SercretKey = ?streamname=live_26495850_4460810&key=925a8432f5f08185d98868920588089c&schedule=rtmp&pflag=1
//String LvieApp = rtmp://txy2.live-push.bilivideo.com/live-bvc/
//public static void streamToRTMP(String SecretKey, String LiveApp, String Resolution, String frame) {
//    System.out.println("摄像头推流开始");
//
//    try {
//        DeviceInfo deviceInfo = getDevice(); // 获取设备信息
//
//        String videoDeviceName = deviceInfo.getVideoDeviceName();
//        String audioDeviceName = deviceInfo.getAudioDeviceName();
//        System.out.println("videoDeviceName: " + videoDeviceName);
//        System.out.println("audioDeviceName: " + audioDeviceName);
//        if (!videoDeviceName.isEmpty()) {
//            String command = "ffmpeg -f dshow -i video=" + videoDeviceName + " -f dshow -i audio=" + audioDeviceName + " -s " + Resolution + " -r " + frame + " -c:v libx264 -c:a aac -f flv " + SecretKey + LiveApp;
//            System.out.println("command: " + command);
//            ProcessBuilder processBuilder = new ProcessBuilder(command.split(" "));
//            processBuilder.redirectErrorStream(true);
//            Process process = processBuilder.start();
//
//            // 读取命令行输出
//            BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
//            String line;
//            while ((line = reader.readLine()) != null) {
//                System.out.println(line);
//            }
//        } else {
//            System.out.println("未找到摄像头设备");
//        }
//    } catch (Exception e) {
//        e.printStackTrace();
//        System.out.println("未知错误，摄像头推流失败");
//    }
//}




//    String video = "C:\\Users\\14308\\Desktop\\DEMO\\orange.mp4";

//    public static void streamVideoToRTMP(String video , String LiveApp , String SecretKey , String Reslution, String frame) {
//        System.out.println("视频推流开始");
//        try {
//            String command = "ffmpeg -re -stream_loop -1 -i "+ video +" -s "+ Reslution +" -r "+frame + " -vcodec libx264 -acodec aac -f flv " +
//                    LiveApp + SecretKey;
//            ProcessBuilder processBuilder = new ProcessBuilder(command.split(" "));
//            processBuilder.redirectErrorStream(true);
//            Process process = processBuilder.start();
//
//            // 读取命令行输出
//            BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
//            String line;
//            while ((line = reader.readLine()) != null) {
//                System.out.println(line);
//            }
//
//            // 等待命令行执行完毕
//            int exitCode = process.waitFor();
//            System.out.println("Exited with error code : " + exitCode);
//        } catch (Exception e) {
//            e.printStackTrace();
//            System.out.println("未知错误，视频推流失败");
//        }
//    }

//    public static DeviceInfo getDevice() {
//        String videoDeviceName = "";
//        String audioDeviceName = "";
//        String command = "ffmpeg -list_devices true -f dshow -i dummy";
//
//        try {
//            ProcessWrapper ffmpeg = new DefaultFFMPEGLocator().createExecutor();
//            ffmpeg.addArgument("-list_devices");
//            ffmpeg.addArgument("true");
//            ffmpeg.addArgument("-f");
//            ffmpeg.addArgument("dshow");
//            ffmpeg.addArgument("-i");
//            ffmpeg.addArgument("dummy");
//            ffmpeg.execute();
//
//            BufferedReader reader = new BufferedReader(new InputStreamReader(ffmpeg.getInputStream()));
//            String line;
//            boolean isVideoDevicesSection = false;
//            boolean isAudioDevicesSection = false;
//
//            while ((line = reader.readLine()) != null) {
//                if (line.contains("video devices")) {
//                    isVideoDevicesSection = true;
//                    isAudioDevicesSection = false;
//                    continue;
//                }
//                if (line.contains("audio devices")) {
//                    isVideoDevicesSection = false;
//                    isAudioDevicesSection = true;
//                    continue;
//                }
//                if (isVideoDevicesSection && !line.startsWith("Devices:")) {
//                    videoDeviceName = removePattern(line.trim(), "\\[.*\\]");
//                    isVideoDevicesSection = false;
//                }
//                if (isAudioDevicesSection && !line.startsWith("Devices:")) {
//                    audioDeviceName = removePattern(line.trim(), "\\[.*\\]");
//                    isAudioDevicesSection = false;
//                }
//            }
//        } catch (IOException e) {
//            // 处理 IO 异常
//            e.printStackTrace();
//        } catch (Exception e) {
//            // 处理其他异常
//            e.printStackTrace();
//        }
//
//        return new DeviceInfo(videoDeviceName, audioDeviceName);
//    }




//    public static DeviceInfo getDevice() {
//        String videoDeviceName = "";
//        String audioDeviceName = "";
//
//        try {
//            String command = "ffmpeg -list_devices true -f dshow -i dummy";
//            ProcessBuilder processBuilder = new ProcessBuilder(command.split(" "));
//            processBuilder.redirectErrorStream(true);
//            Process process = processBuilder.start();
//
//            BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
//            String line;
//            boolean isVideoDevicesSection = false;
//            boolean isAudioDevicesSection = false;
//
//            while ((line = reader.readLine()) != null) {
//                if (line.contains("video devices")) {
//                    isVideoDevicesSection = true;
//                    isAudioDevicesSection = false;
//                    continue;
//                }
//                if (line.contains("audio devices")) {
//                    isVideoDevicesSection = false;
//                    isAudioDevicesSection = true;
//                    continue;
//                }
//                if (isVideoDevicesSection && !line.startsWith("Devices:")) {
//                    videoDeviceName = removePattern(line.trim(), "\\[.*\\]");
//                    isVideoDevicesSection = false;
//                }
//                if (isAudioDevicesSection && !line.startsWith("Devices:")) {
//                    audioDeviceName = removePattern(line.trim(), "\\[.*\\]");
//                    isAudioDevicesSection = false;
//                }
//            }
//        } catch (Exception e) {
//            e.printStackTrace();
//            System.out.println("未知错误，获取设备名称失败");
//        }
//
//        System.out.println("视频设备名称：" + videoDeviceName);
//        System.out.println("音频设备名称：" + audioDeviceName);
//        return new DeviceInfo(videoDeviceName, audioDeviceName);
//    }


//    public static String removePattern(String input, String pattern) {
//        Pattern p = Pattern.compile(pattern);
//        Matcher m = p.matcher(input);
//        return m.replaceAll("").trim();
//    }

//    public static void streamDesktopToRTMP(String LiveApp, String SecretKey, String Reslution, String frame) {
//        System.out.println("桌面推流开始");
//        try {
//            DeviceInfo deviceInfo = getDevice(); // 获取设备信息
//            String audioDeviceName = deviceInfo.getAudioDeviceName();
//            System.out.println("audioDeviceName: " + audioDeviceName);
//            String command = "ffmpeg -f gdigrab -framerate " + frame + " -i desktop -f dshow -i audio=" + audioDeviceName + " -c:v libx264 -preset ultrafast -pix_fmt yuv420p -s " + Reslution + " -c:a aac -b:a 128k -f flv " +
//                    LiveApp + SecretKey;
//            System.out.println("command: " + command);
//            ProcessBuilder processBuilder = new ProcessBuilder(command.split(" "));
//            processBuilder.redirectErrorStream(true);
//            Process process = processBuilder.start();
//
//            // 读取命令行输出
//            BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
//            String line;
//            while ((line = reader.readLine()) != null) {
//                System.out.println(line);
//            }
//
//            // 等待命令行执行完毕
//            int exitCode = process.waitFor();
//            System.out.println("Exited with error code : " + exitCode);
//        } catch (Exception e) {
//            e.printStackTrace();
//            System.out.println("未知错误，桌面推流失败");
//        }
//    }

//    public static class DeviceInfo {
//        private String videoDeviceName;
//        private String audioDeviceName;
//
//        public DeviceInfo(String videoDeviceName, String audioDeviceName) {
//            this.videoDeviceName = videoDeviceName;
//            this.audioDeviceName = audioDeviceName;
//        }
//
//        public String getVideoDeviceName() {
//            return videoDeviceName;
//        }
//
//        public String getAudioDeviceName() {
//            return audioDeviceName;
//        }
//    }


//    public static void stopStreaming() {
//        try {
//            ProcessBuilder processBuilder = new ProcessBuilder("taskkill", "/F", "/IM", "ffmpeg.exe");
//            Process process = processBuilder.start();
//
//            // 等待命令行执行完毕
//            int exitCode = process.waitFor();
//            System.out.println("Exited with error code: " + exitCode);
//        } catch (Exception e) {
//            e.printStackTrace();
//        }
//    }

    public static void stopStreaming() {
        if (ffmpeg != null) {
            try {
                ffmpeg.destroy(); // 停止推流并关闭方法
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    //桌面推流
    public static boolean streamDesktopToRTMP(List<String> appKey, String Reslution, String frame) {
        try {
            // 获取设备信息
            DeviceInfo deviceInfo = getDevice();
            String audioDeviceName = deviceInfo.getSecondAudioInputName();
//            String command = "ffmpeg -f gdigrab -framerate " + frame + " -i desktop -f dshow -i audio=" + audioDeviceName + " -c:v libx264 -preset ultrafast -pix_fmt yuv420p -s " + Reslution + " -c:a aac -b:a 128k -f flv " +
//                    LiveApp + SecretKey;
//            System.out.println("command: " + command);
            String Text = "\"drawtext=text='ZHIBOCESHI':fontsize=36:fontcolor=red:x=20:y=20\"";
            ffmpeg = new DefaultFFMPEGLocator().createExecutor();
            ffmpeg.addArgument("-f");
            ffmpeg.addArgument("gdigrab");
            ffmpeg.addArgument("-framerate");
            ffmpeg.addArgument(frame);
            ffmpeg.addArgument("-i");
            ffmpeg.addArgument("desktop");
            ffmpeg.addArgument("-f");
            ffmpeg.addArgument("dshow");
            ffmpeg.addArgument("-rtbufsize");
            ffmpeg.addArgument("256M");
            ffmpeg.addArgument("-i");
            ffmpeg.addArgument("audio=" + audioDeviceName.replaceAll("\"", ""));
            ffmpeg.addArgument("-c:v");
            ffmpeg.addArgument("h264_nvenc");
            ffmpeg.addArgument("-preset:v");
            ffmpeg.addArgument("fast");
            ffmpeg.addArgument("-pix_fmt");
            ffmpeg.addArgument("yuv420p");
            ffmpeg.addArgument("-s");
            ffmpeg.addArgument(Reslution);
            ffmpeg.addArgument("-c:a");
            ffmpeg.addArgument("aac");
            ffmpeg.addArgument("-b:a");
            ffmpeg.addArgument("128k");
            ffmpeg.addArgument("-vf");
            ffmpeg.addArgument(Text);
            for (String rtmpAddress : appKey) {
                ffmpeg.addArgument("-c:v");
                ffmpeg.addArgument("h264_nvenc");
                ffmpeg.addArgument("-c:a");
                ffmpeg.addArgument("aac");
                ffmpeg.addArgument("-f");
                ffmpeg.addArgument("flv");
                ffmpeg.addArgument("-y");
                ffmpeg.addArgument(rtmpAddress);
            }
            ffmpeg.execute();

            try (BufferedReader br = new BufferedReader(new InputStreamReader(ffmpeg.getErrorStream()))) {
                blockFfmpeg(br);
            }
        } catch (IOException e) {
            System.out.println("桌面推流失败");
            e.printStackTrace();
            return false;
        }
        return true;
    }

    // 推流视频
    public static boolean streamVideoToRTMP(String video , List<String> appKey , String Reslution, String frame) {
        try {
//            String command = "ffmpeg -re -stream_loop -1 -i "+ video +" -s "+ Reslution +" -r "+frame + " -vcodec libx264 -acodec aac -f flv " +
//                    LiveApp + SecretKey;
//            ffmpeg -re -i /root/video/flv/JC-02-output.flv -c:v copy -c:a copy -f flv -y rtmp://your_ip/live/JC-02 -c:v copy -c:a copy -f flv -y rtmp://your_ip/live/JC-03
            String Text = "\"drawtext=text='ZHIBOCESHI':fontsize=36:fontcolor=red:x=20:y=20\"";
            ffmpeg = new DefaultFFMPEGLocator().createExecutor();
            ffmpeg.addArgument("-re");
            ffmpeg.addArgument("-stream_loop");
            ffmpeg.addArgument("-1");
            ffmpeg.addArgument("-i");
            ffmpeg.addArgument(video);
            ffmpeg.addArgument("-vf");
            ffmpeg.addArgument(Text);
            ffmpeg.addArgument("-s");
            ffmpeg.addArgument(Reslution);
            ffmpeg.addArgument("-r");
            ffmpeg.addArgument(frame);
            ffmpeg.addArgument("-vcodec");
            ffmpeg.addArgument("libx264");
            ffmpeg.addArgument("-acodec");
            ffmpeg.addArgument("aac");
//            ffmpeg.addArgument("-f");
//            ffmpeg.addArgument("flv");
//            ffmpeg.addArgument(LiveApp + SecretKey);
            for (String rtmpAddress : appKey) {
                ffmpeg.addArgument("-f");
                ffmpeg.addArgument("flv");
                ffmpeg.addArgument("-y");
                ffmpeg.addArgument(rtmpAddress);
            }
            ffmpeg.execute();

            try (BufferedReader br = new BufferedReader(new InputStreamReader(ffmpeg.getErrorStream()))) {
                blockFfmpeg(br);
            }
        } catch (IOException e) {
            System.out.println("视频推流失败");
            e.printStackTrace();
            return false;
        }
        return true;
    }

    //摄像头推流
    public static boolean streamToRTMP(List<String> appKey, String Resolution, String frame) {
        try {
            DeviceInfo deviceInfo = getDevice(); // 获取设备信息

            String videoDeviceName = deviceInfo.getVideoInputDeviceName();
            String audioDeviceName = deviceInfo.getSecondAudioInputName();
            System.out.println("videoDeviceName: " + videoDeviceName);
            System.out.println("audioDeviceName: " + audioDeviceName);
            String Text = "\"drawtext=text='ZHIBOCESHI':fontsize=36:fontcolor=red:x=20:y=20\"";
            ProcessWrapper ffmpeg = new DefaultFFMPEGLocator().createExecutor();
            if (!videoDeviceName.isEmpty()) {
                ffmpeg.addArgument("-f");
                ffmpeg.addArgument("dshow");
                ffmpeg.addArgument("-rtbufsize");
                ffmpeg.addArgument("256M");
                ffmpeg.addArgument("-i");
                ffmpeg.addArgument("video=" + videoDeviceName.replaceAll("\"", ""));
                ffmpeg.addArgument("-f");
                ffmpeg.addArgument("dshow");
                ffmpeg.addArgument("-i");
                ffmpeg.addArgument("audio=" + audioDeviceName.replaceAll("\"", ""));
                ffmpeg.addArgument("-vf");
                ffmpeg.addArgument(Text);
                ffmpeg.addArgument("-s");
                ffmpeg.addArgument(Resolution);
                ffmpeg.addArgument("-r");
                ffmpeg.addArgument(frame);
                ffmpeg.addArgument("-c:v");
                ffmpeg.addArgument("h264_nvenc");
                ffmpeg.addArgument("-c:a");
                ffmpeg.addArgument("aac");
                for (String rtmpAddress : appKey) {
                    ffmpeg.addArgument("-c:v");
                    ffmpeg.addArgument("h264_nvenc");
                    ffmpeg.addArgument("-c:a");
                    ffmpeg.addArgument("aac");
                    ffmpeg.addArgument("-f");
                    ffmpeg.addArgument("flv");
                    ffmpeg.addArgument("-y");
                    ffmpeg.addArgument(rtmpAddress);
                }
                ffmpeg.execute();
            } else {
                System.out.println("未找到摄像头设备");
            }

            try (BufferedReader br = new BufferedReader(new InputStreamReader(ffmpeg.getErrorStream()))) {
                blockFfmpeg(br);
            }
        } catch (IOException e) {
            System.out.println("摄像头推流失败");
            e.printStackTrace();
            return false;
        }
        return true;
    }


    private static void blockFfmpeg(BufferedReader br) throws IOException {
        String line;
        // 该方法阻塞线程，直至合成成功
        while ((line = br.readLine()) != null) {
            doNothing(line);
        }
    }

    private static void doNothing(String line) {
//         FIXME: 2023/1/31 正式使用时注释掉此行，仅用于观察日志
        System.out.println(line);
    }

    //获取音视频设备信息
    public static DeviceInfo getDevice() throws FrameGrabber.Exception {
        Mixer.Info[] mixerInfos = AudioSystem.getMixerInfo();
        String[] deviceDescriptions = VideoInputFrameGrabber.getDeviceDescriptions();

        String firstAudioInputName = null;
        String secondAudioInputName = null;
        String videoInputDeviceName = null;

        // 获取第一个音频输入设备信息
        if (mixerInfos.length > 0) {
            Mixer.Info firstAudioInputInfo = mixerInfos[0];
            firstAudioInputName = firstAudioInputInfo.getName().replace("Port ", "");
        }
        // 获取第二个音频输入设备信息
        if (mixerInfos.length > 1) {
            Mixer.Info secondAudioInputInfo = mixerInfos[1];
            secondAudioInputName = secondAudioInputInfo.getName().replace("Port ", "");
        }

        // 获取视频输入设备信息
        if (deviceDescriptions != null && deviceDescriptions.length > 0) {
            videoInputDeviceName = deviceDescriptions[0];
        }

        // 创建设备信息对象并返回
        DeviceInfo deviceInfo = new DeviceInfo(firstAudioInputName, secondAudioInputName, videoInputDeviceName);
        return deviceInfo;
    }

    // 设备信息类
    static class DeviceInfo {
        private String firstAudioInputName;
        private String secondAudioInputName;
        private String videoInputDeviceName;

        public DeviceInfo(String firstAudioInputName, String secondAudioInputName, String videoInputDeviceName) {
            this.firstAudioInputName = firstAudioInputName;
            this.secondAudioInputName = secondAudioInputName;
            this.videoInputDeviceName = videoInputDeviceName;
        }

        public String getFirstAudioInputName() {
            return firstAudioInputName;
        }

        public String getSecondAudioInputName() {
            return secondAudioInputName;
        }

        public String getVideoInputDeviceName() {
            return videoInputDeviceName;
        }
    }

}

